package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.product.service.TestService;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import sun.plugin.util.UIUtil;

import javax.xml.namespace.QName;
import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author atguigu-mqx
 */
@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    public void testLock() {
        //  上锁
        RLock lock = redissonClient.getLock("lock");
        //  上锁！
        lock.lock();
        try {
            //  业务逻辑！
            //  获取数据
            String num = this.redisTemplate.opsForValue().get("num");
            //  判断
            if (StringUtils.isEmpty(num)) return;

            //  否则将数据+1 ，并放入缓存！
            int number = Integer.parseInt(num);
            this.redisTemplate.opsForValue().set("num", String.valueOf(++number));
        } catch (NumberFormatException e) {
            e.printStackTrace();
        } finally {
            //  解锁！
            lock.unlock();
        }
    }

    @Override
    public String readLock() {
        //  设置读写锁对象
        RReadWriteLock rwlock = redissonClient.getReadWriteLock("anyRWLock");
        //  上锁:10s 自动解锁
        rwlock.readLock().lock(10,TimeUnit.SECONDS);

        String msg = this.redisTemplate.opsForValue().get("msg");
        //  返回读取到的内容：
        return msg;
    }

    @Override
    public String writeLock() {
        //  设置读写锁对象
        RReadWriteLock rwlock = redissonClient.getReadWriteLock("anyRWLock");
        //  上锁:10s 自动解锁
        rwlock.writeLock().lock(10,TimeUnit.SECONDS);
        //  写入数据.....
        this.redisTemplate.opsForValue().set("msg",UUID.randomUUID().toString());
        return "写入完成.....";
    }

    /**
     * 1.   从缓存中获取一个key 为 num 的数据
     * 2.   判断这个num 是否有数据
     *      true:   将这个数据进行+1 并放入缓存
     *      false:  直接返回即可！
     */
    //  出现了资源抢占！
    //    @Override
    //    public void testLock() {
    //        //  setnx key value
    //        //  Boolean flag = this.redisTemplate.opsForValue().setIfAbsent("lock", "atguigu");
    //        //  setex + setnx  ==> set key value ex timeout nx
    //        String token = UUID.randomUUID().toString();
    //        Boolean flag = this.redisTemplate.opsForValue().setIfAbsent("lock", token, 3, TimeUnit.SECONDS);
    //        if (flag){
    //            //  获取数据
    //            String num = this.redisTemplate.opsForValue().get("num");
    //            //  判断
    //            if (StringUtils.isEmpty(num))   return;
    //
    //            //  否则将数据+1 ，并放入缓存！
    //            int number = Integer.parseInt(num);
    //            this.redisTemplate.opsForValue().set("num",String.valueOf(++number));
    //            //            if (token.equals(this.redisTemplate.opsForValue().get("lock"))){
    //            //                //  释放锁！  充分发挥你的想象力！ index1 进来了。 锁过期了，cpu 执行权限交给index2
    //            //                this.redisTemplate.delete("lock");
    //            //            }
    //            //  准备的脚本
    //            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    //
    //            //  执行：
    //            DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
    //            redisScript.setScriptText(script);
    //            redisScript.setResultType(Long.class);
    //            this.redisTemplate.execute(redisScript, Arrays.asList("lock"),token);
    //
    //        }else {
    //            //  等待重试
    //            try {
    //                Thread.sleep(300);
    //            } catch (InterruptedException e) {
    //                e.printStackTrace();
    //            }
    //            testLock();
    //        }
    //    }
}
